Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 | import { and, eq } from 'drizzle-orm' import { type NextRequest, NextResponse } from 'next/server' import { db, schema } from '@/db' import { getUserId } from '@/lib/viewer' import { generateFlowchartEmbeddings, EMBEDDING_VERSION } from '@/lib/flowcharts/embedding' import { invalidateEmbeddingCache } from '@/lib/flowcharts/embedding-search' import { withAuth } from '@/lib/auth/withAuth' /** * POST /api/teacher-flowcharts/[id]/publish * Publish a draft flowchart * * Validates the flowchart before publishing: * - Definition JSON must be valid * - Required fields must be present * * Returns: { flowchart: TeacherFlowchart } */ export const POST = withAuth(async (_request, { params }) => { try { const { id } = (await params) as { id: string } const userId = await getUserId() // Find the flowchart const existing = await db.query.teacherFlowcharts.findFirst({ where: and(eq(schema.teacherFlowcharts.id, id), eq(schema.teacherFlowcharts.userId, userId)), }) if (!existing) { return NextResponse.json({ error: 'Flowchart not found' }, { status: 404 }) } if (existing.status === 'published') { return NextResponse.json({ error: 'Flowchart is already published' }, { status: 400 }) } if (existing.status === 'archived') { return NextResponse.json({ error: 'Cannot publish an archived flowchart' }, { status: 400 }) } // Validate the definition before publishing let definition try { definition = JSON.parse(existing.definitionJson) } catch { return NextResponse.json({ error: 'Invalid flowchart definition JSON' }, { status: 400 }) } // Basic validation const validationErrors: string[] = [] if (!definition.id) validationErrors.push('Missing flowchart ID in definition') if (!definition.title) validationErrors.push('Missing title in definition') if (!definition.entryNode) validationErrors.push('Missing entry node') if (!definition.nodes || Object.keys(definition.nodes).length === 0) { validationErrors.push('Flowchart must have at least one node') } if (!definition.problemInput) { validationErrors.push('Missing problem input schema') } if (validationErrors.length > 0) { return NextResponse.json( { error: 'Validation failed', details: validationErrors }, { status: 400 } ) } // TODO: Add more comprehensive validation: // - Verify mermaid parses correctly // - Verify all node references are valid // - Verify expressions are valid // - Test with example generation // Find the workshop session to get the original topic description (if any) // This helps with semantic matching - the user's original phrasing captures intent const workshopSession = await db.query.workshopSessions.findFirst({ where: eq(schema.workshopSessions.flowchartId, id), columns: { topicDescription: true, }, }) // Generate embeddings for semantic search // - embedding: full content (title + description + topic + difficulty) // - promptEmbedding: just the original topic description (better for short queries) let embedding: Buffer | null = null let promptEmbedding: Buffer | null = null try { const result = await generateFlowchartEmbeddings({ title: existing.title, description: existing.description, topicDescription: workshopSession?.topicDescription, difficulty: existing.difficulty, }) embedding = result.embedding promptEmbedding = result.promptEmbedding } catch (embeddingError) { // Log but don't fail publish - embedding is nice to have but not required console.error('Failed to generate embeddings for flowchart:', embeddingError) } const now = new Date() const [flowchart] = await db .update(schema.teacherFlowcharts) .set({ status: 'published', publishedAt: now, updatedAt: now, embedding, promptEmbedding, embeddingVersion: embedding ? EMBEDDING_VERSION : null, }) .where(eq(schema.teacherFlowcharts.id, id)) .returning() // Invalidate embedding cache so new flowchart appears in searches if (embedding) { invalidateEmbeddingCache() } return NextResponse.json({ flowchart }) } catch (error) { console.error('Failed to publish teacher flowchart:', error) return NextResponse.json({ error: 'Failed to publish flowchart' }, { status: 500 }) } }) |